package mvc_generator.generator

import java.util.List
import mvc_generator.mVCGenerator.BooleanType
import mvc_generator.mVCGenerator.Data
import mvc_generator.mVCGenerator.DateType
import mvc_generator.mVCGenerator.Declaration
import mvc_generator.mVCGenerator.DoubleType
import mvc_generator.mVCGenerator.IntegerType
import mvc_generator.mVCGenerator.ModelMVC
import mvc_generator.mVCGenerator.SimpleType
import mvc_generator.mVCGenerator.StringType
import org.eclipse.xtext.generator.IFileSystemAccess

class ModelGenerator {

	def void doGenerate(ModelMVC modelMVC, List<String> databasePaths, List<String> businessClassPaths,
		List<String> daosPaths, IFileSystemAccess fsa) {

		generateDatabase(modelMVC, databasePaths, fsa);

		for (Data data : modelMVC.model.datas) {
			generateDataDao(data, daosPaths, fsa);
			generateDataClass(data, businessClassPaths, fsa);
		}
	}

	/**
	 * @arg database: the elist of database tables that describe the database schema.
	 * @arg paths the array of paths where save the file. 
	 * @arg fsa the file generator.
	 */
	private def void generateDatabase(ModelMVC modelMVC, List<String> databasePaths, IFileSystemAccess fsa) {
		var int i = 0;
		var CharSequence fileContent = '''
			CREATE DATABASE «modelMVC.name»
		'''

		for (Data data : modelMVC.model.datas) {
			if (data.declarations.length > 0) {
				fileContent = fileContent + '''
					CREATE TABLE «data.name»(
						`id«data.name.toFirstUpper»` int(10) NOT NULL,
				'''

				while (i < data.declarations.length - 1) {

					fileContent = fileContent + '''
						«computeDatabaseRaw(data.declarations.get(i))» NOT NULL,
					'''

					i = i + 1;
				}

				fileContent = fileContent + '''
					«computeDatabaseRaw(data.declarations.get(data.declarations.length - 1))» NOT NULL
				'''
			}
		}

		fileContent = fileContent + ''');'''

		for (String path : databasePaths) {
			fsa.generateFile(modelMVC.name + path + ".mysql", fileContent);
		}
	}

	private def CharSequence computeDatabaseRaw(Declaration d) {
		var CharSequence result = null;

		if (d.type instanceof IntegerType) {
			result = '''`«d.name»` int(10)''';
		} else if (d.type instanceof DoubleType) {
			result = '''`«d.name»` double(10)''';
		} else if (d.type instanceof StringType) {
			result = '''`«d.name»` varchar(50)''';
		} else if (d.type instanceof BooleanType) {
			result = '''`«d.name»` boolean''';
		} else if (d.type instanceof DateType) {
			result = '''date''';
		} else {
			result = '''@Auto_Generated: Not supported Type''';
		}

		return result;
	}

	private def void generateDataClass(Data data, List<String> businessClassPaths, IFileSystemAccess fsa) {
		var CharSequence result = '''
			package ????;
			
			import ???;
			
			public class «data.name.toFirstUpper» {
				«FOR Declaration d : data.declarations»
					private «generateSimpleType(d.type)»
				«ENDFOR»
			}
		''';
	}

	private def generateSimpleType(SimpleType simpleType) {
		if (simpleType instanceof IntegerType) {
		} else if (simpleType instanceof DoubleType) {
		} else if (simpleType instanceof StringType) {
		} else if (simpleType instanceof BooleanType) {
		} else if (simpleType instanceof DateType) {
		} else {
		}
	}

	private def void generateDataDao(Data data, List<String> daosPaths, IFileSystemAccess fsa) {

		var CharSequence daoContent = '''''';
		var CharSequence addContent = '''''';
		var CharSequence updateContent = '''''';
		var CharSequence deleteContent = '''''';
		var CharSequence getContent = '''''';

		var CharSequence declarationContent = '''''';
		var CharSequence sqlDeclarationContent = '''''';
		var CharSequence interrogationPointSequenceContent = '''''';
		var CharSequence settingPreparedStatementContent = '''''';
		var CharSequence idTableContent = '''''';
		var CharSequence settingDeleteContent = '''''';
		var CharSequence updateValues = '''''';
		var CharSequence settingUpdateContent = '''''';
		var CharSequence settingFieldObjectContent = '''''';

		var boolean isFirst = true;
		var int i = 0;

		declarationContent = '''
			«MVCGeneratorGeneratorUtils.toVoidExpr(isFirst = true)»
				«FOR Declaration declaration : data.declarations»
					«IF isFirst»
						final «declaration.type.stringRepresentation» «declaration.name»«MVCGeneratorGeneratorUtils.toVoidExpr(
				isFirst = false)»
					«ELSE»
						, final «declaration.type.stringRepresentation» «declaration.name»
					«ENDIF»
				«ENDFOR»
		'''

		sqlDeclarationContent = '''
			«MVCGeneratorGeneratorUtils.toVoidExpr(isFirst = true)»
				«FOR Declaration declaration : data.declarations»
					«IF isFirst»
						«declaration.name»«MVCGeneratorGeneratorUtils.toVoidExpr(isFirst = false)»
					«ELSE»
						, «declaration.name»
					«ENDIF»
				«ENDFOR»
		'''

		interrogationPointSequenceContent = '''
			«MVCGeneratorGeneratorUtils.toVoidExpr(isFirst = true)»
				«FOR Declaration declaration : data.declarations»
					«IF isFirst»
						?
					«ELSE»
						, ?
					«ENDIF»
				«ENDFOR»
		'''

		settingPreparedStatementContent = '''
			«MVCGeneratorGeneratorUtils.toVoidExpr(i = 0)»
			«FOR Declaration declaration : data.declarations»
				lPreparedStatementCreation.setLong(«i = i + 1», «declaration.name»);
			«ENDFOR»
		'''

		idTableContent = '''
			id«data.name.toFirstUpper»
		'''

		settingDeleteContent = '''
			lPreparedStatementCreation.setLong(1, id«data.name.toFirstUpper»);
		'''

		updateValues = '''
			«FOR Declaration declaration : data.declarations»
				«IF isFirst»
					«declaration.name»=?
				«ELSE»
					, «declaration.name»=?
				«ENDIF»
			«ENDFOR»
		'''

		settingUpdateContent = '''
			lPreparedStatementCreation.setLong(«data.declarations.length + 1», id«data.name.toFirstUpper»);
		'''

		settingFieldObjectContent = '''
			«FOR Declaration declaration : data.declarations»
				«data.name.toFirstLower».set«declaration.name.toFirstUpper»(rs.get«declaration.type.stringRepresentation.
				toFirstUpper»(«declaration.name»));
				«ENDFOR»	
		'''

		addContent = '''
				public String add«data.name.toFirstUpper»(«declarationContent») {
				try {
				final Context lContext = new InitialContext();
				final DataSource lDataSource = (DataSource) lContext
				.lookup(RESOURCE_JDBC);
				final Connection lConnection = lDataSource.getConnection();
				// adding a new contact
				final PreparedStatement lPreparedStatementCreation = lConnection
				.prepareStatement("INSERT INTO «data.name.toUpperCase»(«sqlDeclarationContent») VALUES(«interrogationPointSequenceContent»)");
				«settingPreparedStatementContent»
				lPreparedStatementCreation.executeUpdate();
				return null;
				} catch (NamingException e) {
				return "NamingException : " + e.getMessage();
				} catch (SQLException e) {
				return "SQLException : " + e.getMessage();
				}
			}
		'''

		deleteContent = '''
				public String delete«data.name.toFirstUpper»(int «idTableContent») {
				try {
				final Context lContext = new InitialContext();
				final DataSource lDataSource = (DataSource) lContext
				.lookup(RESOURCE_JDBC);
				final Connection lConnection = lDataSource.getConnection();
				// adding a new contact
				final PreparedStatement lPreparedStatementCreation = lConnection
				.prepareStatement("DELETE FROM «data.name» WHERE «idTableContent»=?");
				«settingDeleteContent»
				lPreparedStatementCreation.executeUpdate();
				return null;
				} catch (NamingException e) {
				return "NamingException : " + e.getMessage();
				} catch (SQLException e) {
				return "SQLException : " + e.getMessage();
				}
			}
		'''

		updateContent = '''
			public String update«data.name.toFirstUpper»(«declarationContent») {
					try {
					final Context lContext = new InitialContext();
					final DataSource lDataSource = (DataSource) lContext
					.lookup(RESOURCE_JDBC);
					final Connection lConnection = lDataSource.getConnection();
					// adding a new contact
					final PreparedStatement lPreparedStatementCreation = lConnection
					.prepareStatement("UPDATE data.name SET «updateValues» WHERE idTableContent= ?");
					«settingPreparedStatementContent»
					lPreparedStatementCreation.executeUpdate();
					return null;
					} catch (NamingException e) {
					return "NamingException : " + e.getMessage();
					} catch (SQLException e) {
					return "SQLException : " + e.getMessage();
					}
				}
		''';

		getContent = '''
			public «data.name.toFirstUpper» get«data.name.toFirstUpper»(int «idTableContent») {
				Statement statement;
			String query = "SELECT * FROM «data.name» WHERE «idTableContent»= " + «idTableContent»;
			ResultSet rs = null;
			      «data.name.toFirstUpper» «data.name.toFirstLower» = null;
			try {
				
			final Context lContext = new InitialContext();
					final DataSource lDataSource = (DataSource) lContext
					.lookup(RESOURCE_JDBC);
					final Connection lConnection = lDataSource.getConnection();
					 statement = lConnection.createStatement();
					        rs = statement.executeQuery(query);
					        if (rs.next()) {
					            «data.name.toFirstLower» = new  «data.name.toFirstUpper»();
					            «settingFieldObjectContent»
					        }
					 } catch (NamingException e) {
					 	e.printStackTrace();  
					} catch (SQLException e) {
						e.printStackTrace();  
					}
					    return «data.name.toFirstLower»;
					}
		'''

		daoContent = '''
		package domain;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class DAO«data.name.toFirstUpper» {
	private final static String RESOURCE_JDBC = "java:comp/env/jdbc/dsMyDB";
	«addContent»
	«deleteContent»
	«updateContent»
	«getContent»
}
		'''
		for (String path : daosPaths) {
			fsa.generateFile(path, "DAO" + data.name.toFirstUpper());
		}
	}
}
